package com.xncoding.pos.socket;

import java.io.IOException;
import java.net.InetSocketAddress;  
import java.nio.ByteBuffer;  
import java.nio.CharBuffer;  
import java.nio.channels.SelectionKey;  
import java.nio.channels.Selector;  
import java.nio.channels.ServerSocketChannel;  
import java.nio.channels.SocketChannel;  
import java.nio.charset.Charset;  
import java.util.Iterator;  
import java.util.Set;  
  
public class EchoServerNoBlock {  
  
    private int port = 8000;  
    private ServerSocketChannel serverSocketChannel;  
    Selector selector;

    public static void main(String[] args) throws Exception {
        EchoServerNoBlock echoServerNoBlock = new EchoServerNoBlock();
        echoServerNoBlock.service();
    }

    public EchoServerNoBlock() throws Exception {  
        selector = Selector.open();  
        serverSocketChannel = ServerSocketChannel.open();  
        serverSocketChannel.socket().setReuseAddress(true);  
        serverSocketChannel.configureBlocking(false);// 设置通信为非阻塞模式，没有这一配置，则无法实现非阻塞  
        serverSocketChannel.socket().bind(new InetSocketAddress(port));  
        System.out.println("等待连接...");  
    }  
  
    public void service() throws Exception {  
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);  
        while (selector.select() > 0) {  
            Set<SelectionKey> readyKeys = selector.selectedKeys();  
            Iterator<SelectionKey> iterator = readyKeys.iterator();  
            SelectionKey key = null;  
            while (iterator.hasNext()) {  
                try {  
                    key = iterator.next();  
                    iterator.remove();  
                    if (key.isAcceptable()) {  
                        System.out.println("accept");  
                        ServerSocketChannel ssc = (ServerSocketChannel) key  
                                .channel();  
                        SocketChannel sc = ssc.accept();  
                        System.out.println("接收到链接"  
                                + sc.socket().getInetAddress() + ":"  
                                + sc.socket().getPort());  
                        sc.configureBlocking(false);  
                        ByteBuffer buffer = ByteBuffer.allocate(1024);  
                        sc.register(selector, SelectionKey.OP_READ  
                                | SelectionKey.OP_WRITE, buffer);  
                    }  
                    if (key.isReadable()) {  
                        System.out.println("read");  
                        receive(key);  
                    }  
                    if (key.isWritable()) {  
                        send(key);  
                    }  
                } catch (Exception e) {  
                    e.printStackTrace();  
                    if (key != null) {  
                        key.cancel();  
                        key.channel().close();  
                    }  
                }  
            }  
        }  
    }  
  
    /** 
     * 发送消息处理方法 
     * @param key 
     * @throws Exception 
     * @author henushang 
     */  
    public void send(SelectionKey key) throws Exception {  
        ByteBuffer buffer = (ByteBuffer) key.attachment();  
        SocketChannel socketChannel = (SocketChannel) key.channel();  
        buffer.flip();  
        String data = decode(buffer);  
        if (data.indexOf("\r\n") == -1) {  
            return;  
        }  
        String outputData = data.substring(0, data.indexOf("\n") + 1);  
        System.out.println(outputData);  
        ByteBuffer outputBuffer = encode("henushang:" + outputData);  
        while (outputBuffer.hasRemaining()) {  
            socketChannel.write(outputBuffer);  
        }  
        ByteBuffer temp = encode(outputData);  
        buffer.position(temp.limit());  
        buffer.compact();  
  
        if (outputData.equals("byt\r\n")) {  
            key.cancel();  
            socketChannel.close();  
            System.out.println("关闭连接");  
        }  
  
    }  
  
    /** 
     * 接受链接处理方法 
     * @param key 
     * @throws IOException 
     * @author henushang 
     */  
    public void receive(SelectionKey key) throws IOException {  
        SocketChannel sc = (SocketChannel) key.channel();  
        ByteBuffer buffer = (ByteBuffer) key.attachment();  
        ByteBuffer readBuffer = ByteBuffer.allocate(32);  
        sc.read(readBuffer);  
        readBuffer.flip();  
  
        buffer.limit(readBuffer.capacity());  
        buffer.put(readBuffer);  
    }  
  
    static Charset charset = Charset.forName("UTF-8");  
  
    /** 
     * 解码 
     * @param byteBuffer 
     * @return 
     * @author henushang 
     */  
    public static String decode(ByteBuffer byteBuffer) {  
        CharBuffer charBuffer = charset.decode(byteBuffer);  
        return charBuffer.toString();  
    }  
  
    /** 
     * 编码 
     * @param msg 
     * @return 
     * @author henushang 
     */  
    public static ByteBuffer encode(String msg) {  
        return charset.encode(msg);  
    }  
  
}  